{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 生成字典vocab"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "device = 'cuda'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(['the',\n",
       "  'upper',\n",
       "  'clothing',\n",
       "  'has',\n",
       "  'long',\n",
       "  'sleeves',\n",
       "  ',',\n",
       "  'cotton',\n",
       "  'fabric',\n",
       "  'and',\n",
       "  'solid',\n",
       "  'color',\n",
       "  'patterns',\n",
       "  '.',\n",
       "  'the',\n",
       "  'neckline',\n",
       "  'of',\n",
       "  'it',\n",
       "  'is',\n",
       "  'v',\n",
       "  '-shape.',\n",
       "  'the',\n",
       "  'lower',\n",
       "  'clothing',\n",
       "  'is',\n",
       "  'of',\n",
       "  'long',\n",
       "  'length',\n",
       "  '.',\n",
       "  'the',\n",
       "  'fabric',\n",
       "  'is',\n",
       "  'denim',\n",
       "  'and',\n",
       "  'it',\n",
       "  'has',\n",
       "  'solid',\n",
       "  'color',\n",
       "  'patterns',\n",
       "  '.',\n",
       "  'this',\n",
       "  'lady',\n",
       "  'also',\n",
       "  'wears',\n",
       "  'an',\n",
       "  'outer',\n",
       "  'clothing',\n",
       "  ',',\n",
       "  'with',\n",
       "  'cotton',\n",
       "  'fabric',\n",
       "  'and',\n",
       "  'complicated',\n",
       "  'patterns',\n",
       "  '.',\n",
       "  'this',\n",
       "  'female',\n",
       "  'is',\n",
       "  'wearing',\n",
       "  'a',\n",
       "  'ring',\n",
       "  'on',\n",
       "  'her',\n",
       "  'finger',\n",
       "  '.',\n",
       "  'this',\n",
       "  'female',\n",
       "  'has',\n",
       "  'neckwear',\n",
       "  '.'],\n",
       " 70)"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from collections import Counter\n",
    "import re\n",
    "import json\n",
    "import os \n",
    "from nltk.tokenize import RegexpTokenizer\n",
    "\n",
    "\n",
    "def generate_tokens(json_file):  \n",
    "    \"\"\"生成训练集的tokens\"\"\" \n",
    "\n",
    "    # 生成tokens\n",
    "    tokenizer = RegexpTokenizer(r'\\w+|$[0-9.]+|\\S+')\n",
    "    with open(json_file, 'r') as f:\n",
    "         img_captions = json.load(f)\n",
    "         lines =  [ caption.lower() for caption in img_captions.values()]\n",
    "     \n",
    "    return tokenizer.tokenize_sents(lines)\n",
    "\n",
    "file_dir = '../deepfashion-multimodal'  # 数据库文件夹地址\n",
    "tokens = generate_tokens(os.path.join(file_dir,'train_captions.json'))\n",
    "tokens[0],len(tokens[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 生成词表\n",
    "vocab = Counter()\n",
    "\n",
    "for token in tokens:\n",
    "    \n",
    "    vocab.update(token)\n",
    "\n",
    "vocab = {k:v+1 for v,k in enumerate(vocab.keys())}\n",
    "vocab['<pad>'] = 0\n",
    "vocab['<unk>'] = len(vocab)\n",
    "vocab['<start>'] = len(vocab)\n",
    "vocab['<end>'] = len(vocab)\n",
    "\n",
    "with open(os.path.join(file_dir,'vocab.json'),'w') as fw:\n",
    "    json.dump(vocab,fw)\n",
    "\n",
    "id2word = {k:v for v,k in vocab.items()}\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'<pad>'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "id2word[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "111"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vocab_size = len(vocab)\n",
    "vocab_size"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 准备数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.data import Dataset\n",
    "from torchvision import transforms\n",
    "import torch\n",
    "from os import path\n",
    "import numpy as np \n",
    "from PIL import Image\n",
    "import re\n",
    "import json\n",
    "import os \n",
    "# from nltk.tokenize import RegexpTokenize\n",
    "\n",
    "class vit_dataset(Dataset):\n",
    "    def __init__(self,data_path,max_len=80,train=True) -> None:\n",
    "        '''\n",
    "        self.dtat_path:\n",
    "            存放数据集和vocab的文件夹路径\n",
    "\n",
    "        self.tran:\n",
    "            提取训练集还是测试集\n",
    "\n",
    "        self.max_len:\n",
    "            每个样本序列的最长的长度\n",
    "\n",
    "        self.vocab:\n",
    "            对应的单词表,是一个键为单词，值为序号的字典\n",
    "        '''\n",
    "        \n",
    "        self.data_path = data_path\n",
    "        self.train = train\n",
    "        self.max_len = max_len\n",
    "\n",
    "        # 图像预处理，尺寸变为224x224,根据数据集的平均值和方差进行归一化\n",
    "        self.transform = transforms.Compose(\n",
    "    [\n",
    "        transforms.Resize((224,224)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize([0.831, 0.813, 0.806],[0.229, 0.244, 0.252])\n",
    "    ]\n",
    ")\n",
    "        if train:\n",
    "            self.json_dir = path.join(self.data_path,'train_captions.json')\n",
    "        else:\n",
    "            self.json_dir = path.join(self.data_path,'test_captions.json')\n",
    "\n",
    "        with open(self.json_dir, \"r\") as f:\n",
    "            data = json.load(f)\n",
    "\n",
    "        self.images_name = list(data.keys())\n",
    "        self.tokens = self.generate_tokens(data)\n",
    "        \n",
    "        with open(path.join(self.data_path,'vocab.json')) as f:\n",
    "            self.vocab = json.load(f)\n",
    "    \n",
    "    def generate_tokens(self,img_captions):  \n",
    "        \"\"\"\n",
    "        img_captions:读取的字典，keys为图片名，values为图片描述\n",
    "        return : \n",
    "            tokens: 二维列表，(n_captions,n_words)\n",
    "        \"\"\" \n",
    "        # 生成tokens\n",
    "        tokenizer = RegexpTokenizer(r'\\w+|$[0-9.]+|\\S+')\n",
    "        lines =  [ caption.lower() for caption in img_captions.values()]\n",
    "        \n",
    "        return tokenizer.tokenize_sents(lines)\n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        img_dir = path.join(self.data_path,'images',self.images_name[index])\n",
    "        img = Image.open(img_dir)\n",
    "\n",
    "        token_len = len(self.tokens[index])\n",
    "\n",
    "        # 对返回caption进行填充和截断，并在结尾加入结束符\n",
    "        if token_len<= self.max_len:\n",
    "            decode_outputs = torch.tensor([self.vocab.get(w,self.vocab[\"<unk>\"]) for w in self.tokens[index]] + [self.vocab['<end>']] + [self.vocab['<pad>']] *(self.max_len-token_len))\n",
    "            decode_inputs = torch.tensor([self.vocab['<start>']]+[self.vocab.get(w,self.vocab[\"<unk>\"]) for w in self.tokens[index]] + [self.vocab['<pad>']] *(self.max_len-token_len) )\n",
    "\n",
    "        else:\n",
    "            decode_outputs = torch.tensor([self.vocab.get(w,self.vocab['<unk>']) for w in self.tokens[index][:self.max_len]] + [self.vocab['<end>']])\n",
    "            decode_inputs = torch.tensor( [self.vocab['<start>']]+[self.vocab.get(w,self.vocab['<unk>']) for w in self.tokens[index][:self.max_len]])\n",
    "\n",
    "        return self.transform(img),decode_inputs,decode_outputs\n",
    "    \n",
    "    def __len__(self):\n",
    "        return len(self.images_name)\n",
    "\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([3, 224, 224]), torch.Size([81]), torch.Size([81]))"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data = vit_dataset(file_dir)\n",
    "train_data[0][0].shape,train_data[0][1].shape,train_data[0][2].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([109,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,\n",
       "          14,   1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,\n",
       "          22,  14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,\n",
       "          25,  26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,\n",
       "          24,  32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,\n",
       "          14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]),\n",
       " tensor([  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n",
       "           1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,  22,\n",
       "          14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,  25,\n",
       "          26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,  24,\n",
       "          32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,  14,\n",
       "         110,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]))"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[0][1],train_data[0][2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([109,  37,  40,  41,   4,  42,   6,   7,  43,   9,  10,  44,  13,  14,\n",
       "          17,   4,  34,  45,  15,  14,   1,  46,  27,  34,   5,  47,  14,   1,\n",
       "          47,  48,  30,  23,   9,  10,  11,  12,  13,  14,   1,  25,  27,  34,\n",
       "          35,  14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]),\n",
       " tensor([ 37,  40,  41,   4,  42,   6,   7,  43,   9,  10,  44,  13,  14,  17,\n",
       "           4,  34,  45,  15,  14,   1,  46,  27,  34,   5,  47,  14,   1,  47,\n",
       "          48,  30,  23,   9,  10,  11,  12,  13,  14,   1,  25,  27,  34,  35,\n",
       "          14, 110,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n",
       "           0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]))"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[1][1],train_data[1][2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2538"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "test_data = vit_dataset(file_dir,train=False)\n",
    "len(test_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "10155"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(train_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([109,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,\n",
       "          14,   1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,\n",
       "          22,  14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,\n",
       "          25,  26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,\n",
       "          24,  32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,\n",
       "          14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]),\n",
       " tensor([  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n",
       "           1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,  22,\n",
       "          14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,  25,\n",
       "          26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,  24,\n",
       "          32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,  14,\n",
       "         110,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]))"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[0][1],train_data[0][2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([109,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,\n",
       "          14,   1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,\n",
       "          22,  14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,\n",
       "          25,  26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,\n",
       "          24,  32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,\n",
       "          14,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]),\n",
       " tensor([  1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,  14,\n",
       "           1,  15,  16,  17,  18,  19,  20,   1,  21,   3,  18,  16,   5,  22,\n",
       "          14,   1,   9,  18,  23,  10,  17,   4,  11,  12,  13,  14,  24,  25,\n",
       "          26,  27,  28,  29,   3,   7,  30,   8,   9,  10,  31,  13,  14,  24,\n",
       "          32,  18,  33,  34,  35,  36,  37,  38,  14,  24,  32,   4,  39,  14,\n",
       "         110,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0]))"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[0][1],train_data[0][2]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# vit-patchEmbedding层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn \n",
    "class PatchEmbed(nn.Module):\n",
    "    \"\"\"将图像分成几个小块并且Embedding\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    img_size : int\n",
    "        Size of the image (it is a square).\n",
    "\n",
    "    patch_size : int\n",
    "        Size of the patch (it is a square).\n",
    "\n",
    "    in_chans : int\n",
    "        Number of input channels.\n",
    "\n",
    "    embed_dim : int\n",
    "        The emmbedding dimension.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    n_patches : int\n",
    "        Number of patches inside of our image.\n",
    "\n",
    "    proj : nn.Conv2d\n",
    "        Convolutional layer that does both the splitting into patches\n",
    "        and their embedding.\n",
    "    \"\"\"\n",
    "    def __init__(self, img_size, patch_size, in_chans=3, embed_dim=768):\n",
    "        super().__init__()\n",
    "        self.img_size = img_size\n",
    "        self.patch_size = patch_size\n",
    "        self.n_patches = (img_size // patch_size) ** 2\n",
    "\n",
    "\n",
    "        self.proj = nn.Conv2d(\n",
    "                in_chans,\n",
    "                embed_dim,\n",
    "                kernel_size=patch_size,\n",
    "                stride=patch_size,\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        \"\"\"Run forward pass.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        x : torch.Tensor\n",
    "            Shape `(n_samples, in_chans, img_size, img_size)`.\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        torch.Tensor\n",
    "            Shape `(n_samples, n_patches, embed_dim)`.\n",
    "        \"\"\"\n",
    "        x = self.proj(\n",
    "                x\n",
    "            )  # (n_samples, embed_dim, n_patches ** 0.5, n_patches ** 0.5)\n",
    "        x = x.flatten(2)  # (n_samples, embed_dim, n_patches)\n",
    "        x = x.transpose(1, 2)  # (n_samples, n_patches, embed_dim)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 768])"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vitEmbed = PatchEmbed(224,16)\n",
    "ve = vitEmbed(train_data[0][0].unsqueeze(0))\n",
    "ve.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# vit位置信息实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 768])"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pos_embed = torch.ones(1,vitEmbed.n_patches,768)\n",
    "x = ve + pos_embed\n",
    "x.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Attention层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Attention(nn.Module):\n",
    "    \"\"\"Attention mechanism.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    dim : int\n",
    "        The input and out dimension of per token features.\n",
    "\n",
    "    n_heads : int\n",
    "        Number of attention heads.\n",
    "\n",
    "    qkv_bias : bool\n",
    "        If True then we include bias to the query, key and value projections.\n",
    "\n",
    "    attn_p : float\n",
    "        Dropout probability applied to the query, key and value tensors.\n",
    "\n",
    "    proj_p : float\n",
    "        Dropout probability applied to the output tensor.\n",
    "\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    scale : float\n",
    "        Normalizing consant for the dot product.\n",
    "\n",
    "    qkv : nn.Linear\n",
    "        Linear projection for the query, key and value.\n",
    "\n",
    "    proj : nn.Linear\n",
    "        Linear mapping that takes in the concatenated output of all attention\n",
    "        heads and maps it into a new space.\n",
    "\n",
    "    attn_drop, proj_drop : nn.Dropout\n",
    "        Dropout layers.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim, n_heads=8, qkv_bias=True, attn_p=0., proj_p=0.):\n",
    "        super().__init__()\n",
    "        self.n_heads = n_heads\n",
    "        self.dim = dim\n",
    "        self.head_dim = dim // n_heads\n",
    "        self.scale = self.head_dim ** -0.5\n",
    "\n",
    "        self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)\n",
    "        self.attn_drop = nn.Dropout(attn_p)\n",
    "        self.proj = nn.Linear(dim, dim)\n",
    "        self.proj_drop = nn.Dropout(proj_p)\n",
    "\n",
    "    def forward(self, x,attn_mask=None):\n",
    "        \"\"\"Run forward pass.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        x : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "\n",
    "        attn_mask : torch.Tensor\n",
    "                    Shape `(n_samples,n_patches+1,n_patches+1)\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "        \"\"\"\n",
    "        n_samples, n_tokens, dim = x.shape\n",
    "\n",
    "        if dim != self.dim:\n",
    "            raise ValueError\n",
    "\n",
    "        qkv = self.qkv(x)  # (n_samples, n_patches + 1, 3 * dim)\n",
    "        qkv = qkv.reshape(\n",
    "                n_samples, n_tokens, 3, self.n_heads, self.head_dim\n",
    "        )  # (n_smaples, n_patches + 1, 3, n_heads, head_dim)\n",
    "        qkv = qkv.permute(\n",
    "                2, 0, 3, 1, 4\n",
    "        )  # (3, n_samples, n_heads, n_patches + 1, head_dim)\n",
    "\n",
    "        q, k, v = qkv[0], qkv[1], qkv[2]\n",
    "        k_t = k.transpose(-2, -1)  # (n_samples, n_heads, head_dim, n_patches + 1)\n",
    "        dp = (\n",
    "           q @ k_t\n",
    "        ) * self.scale # (n_samples, n_heads, n_patches + 1, n_patches + 1)\n",
    "        if attn_mask!=None:\n",
    "            attn_mask = attn_mask.unsqueeze(1).repeat(1,self.n_heads,1,1)\n",
    "            dp.masked_fill_(attn_mask,-1e9)\n",
    "            \n",
    "        attn = dp.softmax(dim=-1)  # (n_samples, n_heads, n_patches + 1, n_patches + 1)\n",
    "        attn = self.attn_drop(attn)\n",
    "\n",
    "        weighted_avg = attn @ v  # (n_samples, n_heads, n_patches +1, head_dim)\n",
    "        weighted_avg = weighted_avg.transpose(\n",
    "                1, 2\n",
    "        )  # (n_samples, n_patches + 1, n_heads, head_dim)\n",
    "        weighted_avg = weighted_avg.flatten(2)  # (n_samples, n_patches + 1, dim)\n",
    "\n",
    "        x = self.proj(weighted_avg)  # (n_samples, n_patches + 1, dim)\n",
    "        x = self.proj_drop(x)  # (n_samples, n_patches + 1, dim)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 768])"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "at = Attention(dim=768)\n",
    "x_at = at(x)\n",
    "x_at.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# MLP层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "class MLP(nn.Module):\n",
    "    \"\"\"Multilayer perceptron.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    in_features : int\n",
    "        Number of input features.\n",
    "\n",
    "    hidden_features : int\n",
    "        Number of nodes in the hidden layer.\n",
    "\n",
    "    out_features : int\n",
    "        Number of output features.\n",
    "\n",
    "    p : float\n",
    "        Dropout probability.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    fc : nn.Linear\n",
    "        The First linear layer.\n",
    "\n",
    "    act : nn.GELU\n",
    "        GELU activation function.\n",
    "\n",
    "    fc2 : nn.Linear\n",
    "        The second linear layer.\n",
    "\n",
    "    drop : nn.Dropout\n",
    "        Dropout layer.\n",
    "    \"\"\"\n",
    "    def __init__(self, in_features, hidden_features, out_features, p=0.):\n",
    "        super().__init__()\n",
    "        self.fc1 = nn.Linear(in_features, hidden_features)\n",
    "        self.act = nn.GELU()\n",
    "        self.fc2 = nn.Linear(hidden_features, out_features)\n",
    "        self.drop = nn.Dropout(p)\n",
    "\n",
    "    def forward(self, x):\n",
    "        \"\"\"Run forward pass.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        x : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, in_features)`.\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        torch.Tensor\n",
    "            Shape `(n_samples, n_patches +1, out_features)`\n",
    "        \"\"\"\n",
    "        x = self.fc1(\n",
    "                x\n",
    "        ) # (n_samples, n_patches + 1, hidden_features)\n",
    "        x = self.act(x)  # (n_samples, n_patches + 1, hidden_features)\n",
    "        x = self.drop(x)  # (n_samples, n_patches + 1, hidden_features)\n",
    "        x = self.fc2(x)  # (n_samples, n_patches + 1, out_features)\n",
    "        x = self.drop(x)  # (n_samples, n_patches + 1, out_features)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 768])"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mlp = MLP(768,100,768)\n",
    "x_mlp = mlp(x_at)\n",
    "x_mlp.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# vit-Block"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [],
   "source": [
    "class EnBlock(nn.Module):\n",
    "    \"\"\"Transformer block.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    dim : int\n",
    "        Embeddinig dimension.\n",
    "\n",
    "    n_heads : int\n",
    "        Number of attention heads.\n",
    "\n",
    "    mlp_ratio : float\n",
    "        Determines the hidden dimension size of the `MLP` module with respect\n",
    "        to `dim`.\n",
    "\n",
    "    qkv_bias : bool\n",
    "        If True then we include bias to the query, key and value projections.\n",
    "\n",
    "    p, attn_p : float\n",
    "        Dropout probability.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    norm1, norm2 : LayerNorm\n",
    "        Layer normalization.\n",
    "\n",
    "    attn : Attention\n",
    "        Attention module.\n",
    "\n",
    "    mlp : MLP\n",
    "        MLP module.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim, n_heads, mlp_ratio=4.0, qkv_bias=True, p=0., attn_p=0.):\n",
    "        super().__init__()\n",
    "        self.norm1 = nn.LayerNorm(dim, eps=1e-6)\n",
    "        self.attn = Attention(\n",
    "                dim,\n",
    "                n_heads=n_heads,\n",
    "                qkv_bias=qkv_bias,\n",
    "                attn_p=attn_p,\n",
    "                proj_p=p\n",
    "        )\n",
    "        self.norm2 = nn.LayerNorm(dim, eps=1e-6)\n",
    "        hidden_features = int(dim * mlp_ratio)\n",
    "        self.mlp = MLP(\n",
    "                in_features=dim,\n",
    "                hidden_features=hidden_features,\n",
    "                out_features=dim,\n",
    "        )\n",
    "\n",
    "    def forward(self, x):\n",
    "        \"\"\"Run forward pass.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        x : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "        \"\"\"\n",
    "        x = x + self.attn(self.norm1(x))\n",
    "        x = x + self.mlp(self.norm2(x))\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 768])"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "block = EnBlock(768,12)\n",
    "x_b = block(x)\n",
    "x_b.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# vit-Encode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "class VitEncode(nn.Module):\n",
    "    \"\"\"Simplified implementation of the Vision transformer.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    img_size : int\n",
    "        Both height and the width of the image (it is a square).\n",
    "\n",
    "    patch_size : int\n",
    "        Both height and the width of the patch (it is a square).\n",
    "\n",
    "    in_chans : int\n",
    "        Number of input channels.\n",
    "\n",
    "    n_classes : int\n",
    "        Number of classes.\n",
    "\n",
    "    embed_dim : int\n",
    "        Dimensionality of the token/patch embeddings.\n",
    "\n",
    "    depth : int\n",
    "        Number of blocks.\n",
    "\n",
    "    n_heads : int\n",
    "        Number of attention heads.\n",
    "\n",
    "    mlp_ratio : float\n",
    "        Determines the hidden dimension of the `MLP` module.\n",
    "\n",
    "    qkv_bias : bool\n",
    "        If True then we include bias to the query, key and value projections.\n",
    "\n",
    "    p, attn_p : float\n",
    "        Dropout probability.\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    patch_embed : PatchEmbed\n",
    "        Instance of `PatchEmbed` layer.\n",
    "\n",
    "    cls_token : nn.Parameter\n",
    "        Learnable parameter that will represent the first token in the sequence.\n",
    "        It has `embed_dim` elements.\n",
    "\n",
    "    pos_emb : nn.Parameter\n",
    "        Positional embedding of the cls token + all the patches.\n",
    "        It has `(n_patches + 1) * embed_dim` elements.\n",
    "\n",
    "    pos_drop : nn.Dropout\n",
    "        Dropout layer.\n",
    "\n",
    "    blocks : nn.ModuleList\n",
    "        List of `Block` modules.\n",
    "\n",
    "    norm : nn.LayerNorm\n",
    "        Layer normalization.\n",
    "    \"\"\"\n",
    "    def __init__(\n",
    "            self,\n",
    "            img_size=224,\n",
    "            patch_size=16,\n",
    "            in_chans=3,\n",
    "            n_classes=512,\n",
    "            embed_dim=768,\n",
    "            depth=12,\n",
    "            n_heads=12,\n",
    "            mlp_ratio=4.,\n",
    "            qkv_bias=True,\n",
    "            p=0.,\n",
    "            attn_p=0.,\n",
    "    ):\n",
    "        super().__init__()\n",
    "\n",
    "        self.patch_embed = PatchEmbed(\n",
    "                img_size=img_size,\n",
    "                patch_size=patch_size,\n",
    "                in_chans=in_chans,\n",
    "                embed_dim=embed_dim,\n",
    "        )\n",
    "        self.pos_embed = nn.Parameter(\n",
    "                torch.zeros(1,self.patch_embed.n_patches, embed_dim)\n",
    "        )\n",
    "        self.pos_drop = nn.Dropout(p=p)\n",
    "\n",
    "        self.blocks = nn.ModuleList(\n",
    "            [\n",
    "                EnBlock(\n",
    "                    dim=embed_dim,\n",
    "                    n_heads=n_heads,\n",
    "                    mlp_ratio=mlp_ratio,\n",
    "                    qkv_bias=qkv_bias,\n",
    "                    p=p,\n",
    "                    attn_p=attn_p,\n",
    "                )\n",
    "                for _ in range(depth)\n",
    "            ]\n",
    "        )\n",
    "\n",
    "        self.norm = nn.LayerNorm(embed_dim, eps=1e-6)\n",
    "        self.head = nn.Linear(embed_dim, n_classes)\n",
    "\n",
    "\n",
    "    def forward(self, x):\n",
    "        \"\"\"Run the forward pass.\n",
    "\n",
    "        Parameters\n",
    "        ----------\n",
    "        x : torch.Tensor\n",
    "            Shape `(n_samples, in_chans, img_size, img_size)`.\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        logits : torch.Tensor\n",
    "            Logits over all the classes - `(n_samples, n_classes)`.\n",
    "        \"\"\"\n",
    "        n_samples = x.shape[0]\n",
    "        x = self.patch_embed(x)     # (n_samples,n_patches,embed_dim)\n",
    "        x = x + self.pos_embed  # (n_samples,n_patches, embed_dim)\n",
    "        x = self.pos_drop(x)\n",
    "\n",
    "        for block in self.blocks:\n",
    "            x = block(x)\n",
    "\n",
    "        x = self.norm(x)\n",
    "\n",
    "        x = self.head(x) # (n_samples,n_patches,classes)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 196, 512])"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vitT = VitEncode()\n",
    "x_vit = vitT(train_data[0][0].unsqueeze(0))\n",
    "x_vit.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[[0.7209, 0.7209, 0.7209,  ..., 0.6695, 0.6695, 0.6695],\n",
       "          [0.7209, 0.7209, 0.7209,  ..., 0.6695, 0.6695, 0.6695],\n",
       "          [0.7209, 0.7209, 0.7209,  ..., 0.6695, 0.6695, 0.6695],\n",
       "          ...,\n",
       "          [0.6695, 0.6524, 0.6524,  ..., 0.5667, 0.5667, 0.5667],\n",
       "          [0.6695, 0.6524, 0.6524,  ..., 0.5667, 0.5667, 0.5667],\n",
       "          [0.6695, 0.6524, 0.6524,  ..., 0.5839, 0.5839, 0.5667]],\n",
       "\n",
       "         [[0.7503, 0.7503, 0.7503,  ..., 0.7021, 0.7021, 0.7021],\n",
       "          [0.7503, 0.7503, 0.7503,  ..., 0.7021, 0.7021, 0.7021],\n",
       "          [0.7503, 0.7503, 0.7503,  ..., 0.7021, 0.7021, 0.7021],\n",
       "          ...,\n",
       "          [0.6700, 0.6860, 0.6860,  ..., 0.5735, 0.5735, 0.5735],\n",
       "          [0.6700, 0.6860, 0.6860,  ..., 0.5735, 0.5735, 0.5735],\n",
       "          [0.6700, 0.6860, 0.6860,  ..., 0.5896, 0.5896, 0.5735]],\n",
       "\n",
       "         [[0.7543, 0.7543, 0.7543,  ..., 0.7076, 0.7076, 0.7076],\n",
       "          [0.7543, 0.7543, 0.7543,  ..., 0.7076, 0.7076, 0.7076],\n",
       "          [0.7543, 0.7543, 0.7543,  ..., 0.7076, 0.7076, 0.7076],\n",
       "          ...,\n",
       "          [0.6920, 0.6920, 0.6920,  ..., 0.5987, 0.5987, 0.5987],\n",
       "          [0.6920, 0.6920, 0.6920,  ..., 0.5987, 0.5987, 0.5987],\n",
       "          [0.6920, 0.6920, 0.6920,  ..., 0.6142, 0.6142, 0.5987]]]])"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "train_data[0][0].unsqueeze(0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VitEncode(\n",
       "  (patch_embed): PatchEmbed(\n",
       "    (proj): Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))\n",
       "  )\n",
       "  (pos_drop): Dropout(p=0.0, inplace=False)\n",
       "  (blocks): ModuleList(\n",
       "    (0-11): 12 x EnBlock(\n",
       "      (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "      (attn): Attention(\n",
       "        (qkv): Linear(in_features=768, out_features=2304, bias=True)\n",
       "        (attn_drop): Dropout(p=0.0, inplace=False)\n",
       "        (proj): Linear(in_features=768, out_features=768, bias=True)\n",
       "        (proj_drop): Dropout(p=0.0, inplace=False)\n",
       "      )\n",
       "      (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "      (mlp): MLP(\n",
       "        (fc1): Linear(in_features=768, out_features=3072, bias=True)\n",
       "        (act): GELU(approximate='none')\n",
       "        (fc2): Linear(in_features=3072, out_features=768, bias=True)\n",
       "        (drop): Dropout(p=0.0, inplace=False)\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  (norm): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "  (head): Linear(in_features=768, out_features=512, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "vitT"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Embedding层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 81, 512])"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from torch import nn \n",
    "Embed = nn.Embedding(vocab_size,512)\n",
    "output = Embed(train_data[0][1].unsqueeze(0))\n",
    "output.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 1])"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "start = torch.tensor([109]).unsqueeze(0)\n",
    "start.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn \n",
    "import torch \n",
    "import math \n",
    "\n",
    "class PositionalEncoding(nn.Module):\n",
    "    '''对输入caption进行位置编码\n",
    "\n",
    "    '''\n",
    "    def __init__(self, d_model, dropout=0.1, max_len=5000):\n",
    "        super(PositionalEncoding, self).__init__()\n",
    "        self.dropout = nn.Dropout(p=dropout)\n",
    "\n",
    "        pe = torch.zeros(max_len, d_model)\n",
    "        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)\n",
    "        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))\n",
    "        pe[:, 0::2] = torch.sin(position * div_term)\n",
    "        pe[:, 1::2] = torch.cos(position * div_term)\n",
    "        pe = pe.unsqueeze(0).transpose(0, 1)\n",
    "        self.register_buffer('pe', pe)\n",
    "\n",
    "    def forward(self, x):\n",
    "        '''\n",
    "        x: [seq_len, batch_size, d_model]\n",
    "        '''\n",
    "        x = x + self.pe[:x.size(0), :]\n",
    "        return self.dropout(x)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([80, 1, 512])"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pe = PositionalEncoding(512)\n",
    "pe.pe[:80,:].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_attn_pad_mask(seq_q, seq_k):\n",
    "    '''\n",
    "    seq_q: [batch_size, seq_len]\n",
    "    seq_k: [batch_size, seq_len]\n",
    "    seq_len could be src_len or it could be tgt_len\n",
    "    seq_len in seq_q and seq_len in seq_k maybe not equal\n",
    "    '''\n",
    "    batch_size, len_q = seq_q.size()\n",
    "    batch_size, len_k = seq_k.size()\n",
    "    # eq(zero) is PAD token\n",
    "    pad_attn_mask = seq_k.data.eq(0).unsqueeze(1)  # [batch_size, 1, len_k], False is masked\n",
    "    return pad_attn_mask.expand(batch_size, len_q, len_k)  # [batch_size, len_q, len_k]\n",
    "\n",
    "def get_attn_subsequence_mask(seq):\n",
    "    '''\n",
    "    seq: [batch_size, tgt_len]\n",
    "    '''\n",
    "    attn_shape = [seq.size(0), seq.size(1), seq.size(1)]\n",
    "    subsequence_mask = np.triu(np.ones(attn_shape), k=1) # Upper triangular matrix\n",
    "    subsequence_mask = torch.from_numpy(subsequence_mask).byte()\n",
    "    return subsequence_mask # [batch_size, tgt_len, tgt_len]    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "tensor([[[0, 1, 1],\n",
       "         [0, 0, 1],\n",
       "         [0, 0, 0]],\n",
       "\n",
       "        [[0, 1, 1],\n",
       "         [0, 0, 1],\n",
       "         [0, 0, 0]]], dtype=torch.uint8)"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "import numpy as np\n",
    "seq = torch.arange(2*3).reshape(2,3)\n",
    "get_attn_subsequence_mask(seq)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Attention-transformer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Attention_tf(nn.Module):\n",
    "    \"\"\"Attention mechanism.\n",
    "\n",
    "    Parameters\n",
    "    ----------\n",
    "    dim : int\n",
    "        The input and out dimension of per token features.\n",
    "\n",
    "    n_heads : int\n",
    "        Number of attention heads.\n",
    "\n",
    "    qkv_bias : bool\n",
    "        If True then we include bias to the query, key and value projections.\n",
    "\n",
    "    attn_p : float\n",
    "        Dropout probability applied to the query, key and value tensors.\n",
    "\n",
    "    proj_p : float\n",
    "        Dropout probability applied to the output tensor.\n",
    "\n",
    "\n",
    "    Attributes\n",
    "    ----------\n",
    "    scale : float\n",
    "        Normalizing consant for the dot product.\n",
    "\n",
    "    qkv : nn.Linear\n",
    "        Linear projection for the query, key and value.\n",
    "\n",
    "    proj : nn.Linear\n",
    "        Linear mapping that takes in the concatenated output of all attention\n",
    "        heads and maps it into a new space.\n",
    "\n",
    "    attn_drop, proj_drop : nn.Dropout\n",
    "        Dropout layers.\n",
    "    \"\"\"\n",
    "    def __init__(self, dim, n_heads=8, qkv_bias=True, attn_p=0., proj_p=0.):\n",
    "        super().__init__()\n",
    "        self.n_heads = n_heads\n",
    "        self.dim = dim\n",
    "        self.head_dim = dim // n_heads\n",
    "        self.scale = self.head_dim ** -0.5\n",
    "\n",
    "        self.W_Q = nn.Linear(dim,dim,bias = qkv_bias)\n",
    "        self.W_K = nn.Linear(dim,dim,bias = qkv_bias)\n",
    "        self.W_V = nn.Linear(dim,dim,bias = qkv_bias)\n",
    "        self.attn_drop = nn.Dropout(attn_p)\n",
    "        self.proj = nn.Linear(dim, dim)\n",
    "        self.proj_drop = nn.Dropout(proj_p)\n",
    "\n",
    "    def forward(self, input_Q,input_K,input_V,attn_mask=None):\n",
    "        \"\"\"Run forward pass.\n",
    "        Parameters\n",
    "        ----------\n",
    "        input_Q : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "\n",
    "        input_K : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "\n",
    "        input_V : torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "\n",
    "        attn_mask : torch.Tensor\n",
    "                    Shape `(n_samples,n_patches+1,n_patches+1)\n",
    "\n",
    "        Returns\n",
    "        -------\n",
    "        torch.Tensor\n",
    "            Shape `(n_samples, n_patches + 1, dim)`.\n",
    "        \"\"\"\n",
    "\n",
    "        n_samples,  dim = input_Q.shape[0],input_Q.shape[2]\n",
    "\n",
    "        if dim != self.dim:\n",
    "            raise ValueError\n",
    "\n",
    "        q = self.W_Q(input_Q).reshape(n_samples,-1,self.n_heads,self.head_dim).transpose(1,2)\n",
    "        k = self.W_K(input_K).reshape(n_samples,-1,self.n_heads,self.head_dim).transpose(1,2)\n",
    "        v = self.W_V(input_V).reshape(n_samples,-1,self.n_heads,self.head_dim).transpose(1,2)\n",
    "        \n",
    "        k_t = k.transpose(-2, -1)  # (n_samples, n_heads, head_dim, n_patches + 1)\n",
    "        dp = (\n",
    "           q @ k_t\n",
    "        ) * self.scale # (n_samples, n_heads, n_patches + 1, n_patches + 1)\n",
    "        if attn_mask!=None:\n",
    "            attn_mask = attn_mask.unsqueeze(1).repeat(1,self.n_heads,1,1)\n",
    "            dp.masked_fill_(attn_mask,-1e9)\n",
    "            \n",
    "        attn = dp.softmax(dim=-1)  # (n_samples, n_heads, n_patches + 1, n_patches + 1)\n",
    "        attn = self.attn_drop(attn)\n",
    "\n",
    "        weighted_avg = attn @ v  # (n_samples, n_heads, n_patches +1, head_dim)\n",
    "        weighted_avg = weighted_avg.transpose(\n",
    "                1, 2\n",
    "        )  # (n_samples, n_patches + 1, n_heads, head_dim)\n",
    "        weighted_avg = weighted_avg.flatten(2)  # (n_samples, n_patches + 1, dim)\n",
    "\n",
    "        x = self.proj(weighted_avg)  # (n_samples, n_patches + 1, dim)\n",
    "        x = self.proj_drop(x)  # (n_samples, n_patches + 1, dim)\n",
    "\n",
    "        return x"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DeBlock层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [],
   "source": [
    "class DeBlock(nn.Module):\n",
    "    def __init__(self,dim,n_heads,mlp_ratio=4.0,qkv_bias=True,p=0.,attn_p=0.):\n",
    "        super().__init__()\n",
    "        self.norm1 = nn.LayerNorm(dim,eps=1e-6)\n",
    "        self.dec_self_attn = Attention_tf(\n",
    "            dim,\n",
    "            n_heads=n_heads,\n",
    "            qkv_bias=qkv_bias,\n",
    "            attn_p=attn_p,\n",
    "            proj_p=p\n",
    "            )\n",
    "        self.dec_enc_attn = Attention_tf(\n",
    "            dim,\n",
    "            n_heads=n_heads,\n",
    "            qkv_bias=qkv_bias,\n",
    "            attn_p=attn_p,\n",
    "            proj_p=p\n",
    "            )\n",
    "        self.norm2 = nn.LayerNorm(dim,eps=1e-6)\n",
    "        hidden_features = int(dim*mlp_ratio)\n",
    "        self.pos_ffn = MLP(\n",
    "            in_features=dim,\n",
    "            hidden_features=hidden_features,\n",
    "            out_features=dim\n",
    "        )\n",
    "        self.norm3 = nn.LayerNorm(dim,eps=1e-6)\n",
    "    \n",
    "    def forward(self,dec_inputs,enc_outputs,dec_self_attn_mask):\n",
    "        '''\n",
    "        dec_inputs: [n_samples,tgt_len,dim]\n",
    "        enc_inputs: [n_samples,src_len,dim]\n",
    "        dec_self_attn_mask: [n_samples,tgt_len,tgt_len]\n",
    "        dec_enc_attn_mask: [n_samples,src_len,src_len]\n",
    "        '''\n",
    "        dec_outputs = self.norm1(dec_inputs + self.dec_self_attn(dec_inputs,dec_inputs,dec_inputs,dec_self_attn_mask))\n",
    "        dec_outputs = self.norm2(dec_outputs+self.dec_enc_attn(dec_outputs,enc_outputs,enc_outputs))\n",
    "        dec_outputs = self.norm3(dec_outputs+self.pos_ffn(dec_outputs))\n",
    "        \n",
    "        return dec_outputs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# TransformerDncode层"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [],
   "source": [
    "class TransformerDecode(nn.Module):\n",
    "    def __init__(\n",
    "            self,\n",
    "            vocab_size=111,\n",
    "            embed_dim=512,\n",
    "            n_heads=8,\n",
    "            mlp_ratio=4,\n",
    "            qkv_bias=True,\n",
    "            p=0.,\n",
    "            attn_p=0.,\n",
    "            depth=6,\n",
    "            max_len=80\n",
    "            ):\n",
    "        super().__init__()\n",
    "        self.tgt_emb = nn.Embedding(vocab_size,embed_dim)\n",
    "        self.pos_emb = PositionalEncoding(embed_dim)\n",
    "        self.layers = nn.ModuleList(\n",
    "            [\n",
    "                DeBlock(\n",
    "                    dim=embed_dim,\n",
    "                    n_heads=n_heads,\n",
    "                    mlp_ratio=mlp_ratio,\n",
    "                    qkv_bias=qkv_bias,\n",
    "                    p=p,\n",
    "                    attn_p=attn_p\n",
    "                )\n",
    "                for _ in range(depth)\n",
    "            ]\n",
    "        )\n",
    "\n",
    "    def forward(self,dec_inputs,enc_outputs):\n",
    "        '''\n",
    "        dec_inputs: [n_samples, tgt_len]\n",
    "        enc_intpus: [n_samples, src_len]\n",
    "        enc_outputs: [n_samples, src_len, embed_dim]        \n",
    "        '''\n",
    "        dec_outputs = self.tgt_emb(dec_inputs) # [n_sample, tgt_len, embed_dim]\n",
    "        dec_outputs = self.pos_emb(dec_outputs.transpose(0, 1)).transpose(0, 1) # [n_sample, tgt_len, embed_dim]\n",
    "        dec_self_attn_pad_mask = get_attn_pad_mask(dec_inputs, dec_inputs).to(device) # [batch_size, tgt_len, tgt_len]\n",
    "        dec_self_attn_subsequence_mask = get_attn_subsequence_mask(dec_inputs).to(device) # [batch_size, tgt_len, tgt_len]\n",
    "        dec_self_attn_mask = torch.gt((dec_self_attn_pad_mask + dec_self_attn_subsequence_mask), 0)# [batch_size, tgt_len, tgt_len]\n",
    "\n",
    "        # dec_enc_attn_mask = get_attn_pad_mask(dec_inputs, enc_inputs) # [batc_size, tgt_len, src_len]\n",
    "\n",
    "        for layer in self.layers:\n",
    "            # dec_outputs: [batch_size, tgt_len, d_model], dec_self_attn: [batch_size, n_heads, tgt_len, tgt_len], dec_enc_attn: [batch_size, h_heads, tgt_len, src_len]\n",
    "            dec_outputs = layer(dec_outputs, enc_outputs, dec_self_attn_mask)\n",
    "            \n",
    "        return dec_outputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "TransformerDecode(\n",
       "  (tgt_emb): Embedding(111, 512)\n",
       "  (pos_emb): PositionalEncoding(\n",
       "    (dropout): Dropout(p=0.1, inplace=False)\n",
       "  )\n",
       "  (layers): ModuleList(\n",
       "    (0-5): 6 x DeBlock(\n",
       "      (norm1): LayerNorm((512,), eps=1e-06, elementwise_affine=True)\n",
       "      (dec_self_attn): Attention_tf(\n",
       "        (W_Q): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (W_K): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (W_V): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (attn_drop): Dropout(p=0.0, inplace=False)\n",
       "        (proj): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (proj_drop): Dropout(p=0.0, inplace=False)\n",
       "      )\n",
       "      (dec_enc_attn): Attention_tf(\n",
       "        (W_Q): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (W_K): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (W_V): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (attn_drop): Dropout(p=0.0, inplace=False)\n",
       "        (proj): Linear(in_features=512, out_features=512, bias=True)\n",
       "        (proj_drop): Dropout(p=0.0, inplace=False)\n",
       "      )\n",
       "      (norm2): LayerNorm((512,), eps=1e-06, elementwise_affine=True)\n",
       "      (pos_ffn): MLP(\n",
       "        (fc1): Linear(in_features=512, out_features=2048, bias=True)\n",
       "        (act): GELU(approximate='none')\n",
       "        (fc2): Linear(in_features=2048, out_features=512, bias=True)\n",
       "        (drop): Dropout(p=0.0, inplace=False)\n",
       "      )\n",
       "      (norm3): LayerNorm((512,), eps=1e-06, elementwise_affine=True)\n",
       "    )\n",
       "  )\n",
       ")"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "tfdcode = TransformerDecode(vocab_size=vocab_size,embed_dim=512).to(device)\n",
    "tfdcode"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "start = torch.arange(1*2).reshape(1,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 2, 512])"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dec_inputs = start.to(device)\n",
    "enc_outputs = x_vit.to(device)\n",
    "x_tf = tfdcode(dec_inputs,enc_outputs)\n",
    "x_tf.shape  # (n_samples,src_len,vocab_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 2]), torch.Size([1, 196, 512]))"
      ]
     },
     "execution_count": 53,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "dec_inputs.shape,enc_outputs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import nn\n",
    "class VitTransformer(nn.Module):\n",
    "    def __init__(\n",
    "            self,\n",
    "            img_size=224,\n",
    "            patch_size=16,\n",
    "            in_chans=3,\n",
    "            embed_dim=768,\n",
    "            encode_depth=12,\n",
    "            encode_n_heads=8,\n",
    "            mlp_ratio=4.0,\n",
    "            qkv_bias=True,\n",
    "            p=0.3,\n",
    "            attn_p=0.3,\n",
    "            vocab_size=111,\n",
    "            decode_n_headers=8,\n",
    "            decode_depth=12,\n",
    "            max_len=80):\n",
    "        super().__init__()\n",
    "        self.encoder = VitEncode(\n",
    "            img_size=img_size,\n",
    "            patch_size=patch_size,\n",
    "            in_chans=in_chans,\n",
    "            n_classes=embed_dim,\n",
    "            embed_dim=embed_dim,\n",
    "            depth=encode_depth,\n",
    "            n_heads=encode_n_heads,\n",
    "            mlp_ratio=mlp_ratio,\n",
    "            qkv_bias=qkv_bias,\n",
    "            p=p,\n",
    "            attn_p=attn_p\n",
    "        ).to(device)\n",
    "        self.decoder = TransformerDecode(\n",
    "            vocab_size=vocab_size,\n",
    "            embed_dim=embed_dim,\n",
    "            n_heads=decode_n_headers,\n",
    "            mlp_ratio=mlp_ratio,\n",
    "            qkv_bias=qkv_bias,\n",
    "            p=p,\n",
    "            attn_p=attn_p,\n",
    "            depth=decode_depth,\n",
    "            max_len=max_len\n",
    "        ).to(device)\n",
    "        self.projection = nn.Linear(embed_dim, vocab_size, bias=qkv_bias).to(device)\n",
    "    def forward(self, enc_inputs, dec_inputs):\n",
    "        '''\n",
    "        enc_inputs: [batch_size, src_len]\n",
    "        dec_inputs: [batch_size, tgt_len]\n",
    "        '''\n",
    "        # tensor to store decoder outputs\n",
    "        # outputs = torch.zeros(batch_size, tgt_len, tgt_vocab_size)\n",
    "        \n",
    "        # enc_outputs: [n_samples, src_len, embed_dim]\n",
    "        enc_outputs = self.encoder(enc_inputs)\n",
    "        # dec_outpus: [n_samples, tgt_len, embed_dim]\n",
    "        dec_outputs = self.decoder(dec_inputs, enc_outputs)\n",
    "        dec_logits = self.projection(dec_outputs) # dec_logits: [n_samples, tgt_len, tgt_vocab_size]\n",
    "        return dec_logits.view(-1, dec_logits.size(-1))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "VitTransformer(\n",
       "  (encoder): VitEncode(\n",
       "    (patch_embed): PatchEmbed(\n",
       "      (proj): Conv2d(3, 768, kernel_size=(16, 16), stride=(16, 16))\n",
       "    )\n",
       "    (pos_drop): Dropout(p=0.3, inplace=False)\n",
       "    (blocks): ModuleList(\n",
       "      (0-11): 12 x EnBlock(\n",
       "        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "        (attn): Attention(\n",
       "          (qkv): Linear(in_features=768, out_features=2304, bias=True)\n",
       "          (attn_drop): Dropout(p=0.3, inplace=False)\n",
       "          (proj): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (proj_drop): Dropout(p=0.3, inplace=False)\n",
       "        )\n",
       "        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "        (mlp): MLP(\n",
       "          (fc1): Linear(in_features=768, out_features=3072, bias=True)\n",
       "          (act): GELU(approximate='none')\n",
       "          (fc2): Linear(in_features=3072, out_features=768, bias=True)\n",
       "          (drop): Dropout(p=0.0, inplace=False)\n",
       "        )\n",
       "      )\n",
       "    )\n",
       "    (norm): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "    (head): Linear(in_features=768, out_features=768, bias=True)\n",
       "  )\n",
       "  (decoder): TransformerDecode(\n",
       "    (tgt_emb): Embedding(111, 768)\n",
       "    (pos_emb): PositionalEncoding(\n",
       "      (dropout): Dropout(p=0.1, inplace=False)\n",
       "    )\n",
       "    (layers): ModuleList(\n",
       "      (0-11): 12 x DeBlock(\n",
       "        (norm1): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "        (dec_self_attn): Attention_tf(\n",
       "          (W_Q): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (W_K): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (W_V): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (attn_drop): Dropout(p=0.3, inplace=False)\n",
       "          (proj): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (proj_drop): Dropout(p=0.3, inplace=False)\n",
       "        )\n",
       "        (dec_enc_attn): Attention_tf(\n",
       "          (W_Q): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (W_K): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (W_V): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (attn_drop): Dropout(p=0.3, inplace=False)\n",
       "          (proj): Linear(in_features=768, out_features=768, bias=True)\n",
       "          (proj_drop): Dropout(p=0.3, inplace=False)\n",
       "        )\n",
       "        (norm2): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "        (pos_ffn): MLP(\n",
       "          (fc1): Linear(in_features=768, out_features=3072, bias=True)\n",
       "          (act): GELU(approximate='none')\n",
       "          (fc2): Linear(in_features=3072, out_features=768, bias=True)\n",
       "          (drop): Dropout(p=0.0, inplace=False)\n",
       "        )\n",
       "        (norm3): LayerNorm((768,), eps=1e-06, elementwise_affine=True)\n",
       "      )\n",
       "    )\n",
       "  )\n",
       "  (projection): Linear(in_features=768, out_features=111, bias=True)\n",
       ")"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model = VitTransformer()\n",
    "model.to(device)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(torch.Size([1, 3, 224, 224]), torch.Size([1, 81]))"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "enc_inputs = train_data[0][0].unsqueeze(0).to(device)\n",
    "dec_inputs = train_data[0][1].unsqueeze(0).to(device)\n",
    "enc_inputs.shape,dec_inputs.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([81, 111])"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model(enc_inputs,dec_inputs).shape  # (n_samples*tgt_len,vocab_size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch.utils.data import DataLoader\n",
    "loader = DataLoader(train_data,4,True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "from torch import optim\n",
    "model = VitTransformer().to(device)\n",
    "criterion = nn.CrossEntropyLoss(ignore_index=0)\n",
    "optim.Adam()\n",
    "optimizer = optim.SGD(model.parameters(), lr=6e-4, momentum=0.99)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Rouge-L实现"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [],
   "source": [
    "from nltk.util import ngrams\n",
    "def rouge_l(preds,true_va,beta):\n",
    "    '''\n",
    "    Parameters\n",
    "    ----------\n",
    "    preds : torch.Tensor\n",
    "        Shape `(n_samples,pres_seq_len)`\n",
    "    true_va : torch.Tensor\n",
    "        Shape `(n_samples,true_seq_len)\n",
    "\n",
    "    Returns\n",
    "    -------\n",
    "    P : torch.Tensor\n",
    "        Shape `() \n",
    "    '''\n",
    "    n_samples = preds.shape[0]\n",
    "    num = min(preds.shape[1],true_va.shape[1])\n",
    "    lcs = torch.zeros(n_samples)\n",
    "    for i in range(n_samples):\n",
    "        for n_g in range(1,num+1):\n",
    "            preds_gram = set(ngrams(preds[i].tolist(),n_g))\n",
    "            true_gram = set(ngrams(true_va[i].tolist(),n_g))\n",
    "            if len(preds_gram.intersection(true_gram))!=0:\n",
    "                lcs[i] = n_g \n",
    "    r = lcs/preds.shape[1]\n",
    "    p = lcs/true_va.shape[1]\n",
    "    f = (1+beta**2)*r*p/(r+beta**2*p)\n",
    "    return   r,p,f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([[0, 1, 2],\n",
       "         [3, 4, 5]]),\n",
       " tensor([[1, 2, 3],\n",
       "         [4, 5, 6]]),\n",
       " (tensor([0.6667, 0.6667]),\n",
       "  tensor([0.6667, 0.6667]),\n",
       "  tensor([0.6667, 0.6667])))"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "a = torch.arange(6).reshape(2,3)\n",
    "b = torch.arange(1,7).reshape(2,3)\n",
    "a,b,rouge_l(a,b,100)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 训练"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "# for epoch in range(100):\n",
    "#     loss_eva = []\n",
    "#     for enc_inputs, dec_inputs, dec_outputs in loader:\n",
    "#       '''\n",
    "#       enc_inputs: [batch_size, src_len]\n",
    "#       dec_inputs: [batch_size, tgt_len]\n",
    "#       dec_outputs: [batch_size, tgt_len]\n",
    "#       '''\n",
    "#       enc_inputs, dec_inputs, dec_outputs = enc_inputs.to(device), dec_inputs.to(device), dec_outputs.to(device)\n",
    "#       # outputs: [batch_size * tgt_len, tgt_vocab_size]\n",
    "#       outputs = model(enc_inputs, dec_inputs)\n",
    "#       loss = criterion(outputs, dec_outputs.view(-1))\n",
    "\n",
    "#       optimizer.zero_grad()\n",
    "#       loss.backward()\n",
    "#       optimizer.step()\n",
    "#       loss_eva.append(loss)\n",
    "#     print('Epoch:', '%04d' % (epoch + 1), 'loss =', '{:.6f}'.format(sum(loss)/len(loss)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<All keys matched successfully>"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "model.load_state_dict(torch.load('modelv5.pt'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 预测"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [],
   "source": [
    "def greedy_decoder(model, enc_input, start_symbol,tgt_vocab):\n",
    "    \"\"\"贪心编码\n",
    "    For simplicity, a Greedy Decoder is Beam search when K=1. This is necessary for inference as we don't know the\n",
    "    target sequence input. Therefore we try to generate the target input word by word, then feed it into the transformer.\n",
    "    Starting Reference: http://nlp.seas.harvard.edu/2018/04/03/attention.html#greedy-decoding\n",
    "    :param model: Transformer Model\n",
    "    :param enc_input: The encoder input\n",
    "    :param start_symbol: The start symbol. In this example it is 'S' which corresponds to index 4\n",
    "    :return: The target input\n",
    "    \"\"\"\n",
    "    enc_outputs = model.encoder(enc_input)\n",
    "    # 初始化一个空的tensor: tensor([], size=(1, 0), dtype=torch.int64)\n",
    "    dec_input = torch.zeros(1, 0,dtype=int)\n",
    "    terminal = False\n",
    "    next_symbol = start_symbol\n",
    "    while not terminal:\n",
    "        # 预测阶段：dec_input序列会一点点变长（每次添加一个新预测出来的单词）\n",
    "        dec_input = torch.cat([dec_input.to(device), torch.tensor([[next_symbol]], dtype=int).to(device)],-1)\n",
    "        if int(dec_input.shape[-1]) > 80:\n",
    "            terminal= False\n",
    "            break\n",
    "        \n",
    "        dec_outputs = model.decoder(dec_input, enc_outputs)\n",
    "        projected = model.projection(dec_outputs)\n",
    "        prob = projected.squeeze(0).max(dim=-1, keepdim=False)[1]\n",
    "        # 增量更新（我们希望重复单词预测结果是一样的）\n",
    "        # 我们在预测是会选择性忽略重复的预测的词，只摘取最新预测的单词拼接到输入序列中\n",
    "        # 拿出当前预测的单词(数字)。我们用x'_t对应的输出z_t去预测下一个单词的概率，不用z_1,z_2..z_{t-1}\n",
    "        next_word = prob.data[-1]\n",
    "        next_symbol = next_word\n",
    "        if next_symbol == tgt_vocab[\"<end>\"] :\n",
    "            terminal = True\n",
    "        # print(next_word)\n",
    "\n",
    "    # greedy_dec_predict = torch.cat(\n",
    "    #     [dec_input.to(device), torch.tensor([[next_symbol]], dtype=enc_input.dtype).to(device)],\n",
    "    #     -1)\n",
    "    greedy_dec_predict = dec_input[:, 1:]\n",
    "    return greedy_dec_predict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "transform_img = transforms.Compose(\n",
    "    [\n",
    "        transforms.Resize((224,224)),\n",
    "        transforms.ToTensor(),\n",
    "        transforms.Normalize([0.831, 0.813, 0.806],[0.229, 0.244, 0.252])\n",
    "    ])\n",
    "img_dir = r'E:\\py_code\\img desctiption generate\\deepfashion-multimodal\\images\\WOMEN-Jackets_Coats-id_00006499-03_7_additional.jpg'\n",
    "img = Image.open(img_dir)\n",
    "enc_inputs = transform_img(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x153c2c59a90>"
      ]
     },
     "execution_count": 79,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import  matplotlib.pyplot as plt\n",
    "plt.imshow(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "==============================\n",
      "利用训练好的Vit-Transformer模型对图片进行描述 \n",
      "the shirt this woman wears has long sleeves and it is with cotton fabric and solid color patterns . the neckline of the shirt is round . this woman wears a three -point shorts , with denim fabric and pure color patterns . the outer clothing is with cotton fabric and solid color patterns . the female wears a ring . "
     ]
    }
   ],
   "source": [
    "\n",
    "print(\"=\"*30)\n",
    "print(\"利用训练好的Vit-Transformer模型对图片进行描述 \")\n",
    "\n",
    "greedy_dec_predict = greedy_decoder(model, enc_inputs.unsqueeze(0).to(device), start_symbol=vocab[\"<start>\"],tgt_vocab=vocab)   # (n_samples,seq_len)\n",
    "# print(enc_inputs[i], '->', greedy_dec_predict.squeeze())\n",
    "# rouge_l(enc_inputs.unsqueeze(0),)\n",
    "for n in greedy_dec_predict.squeeze():\n",
    "    print(id2word[n.item()],end=' ') "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "torch.Size([1, 47])"
      ]
     },
     "execution_count": 97,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "greedy_dec_predict = greedy_decoder(model, train_data[0][0].unsqueeze(0).to(device), start_symbol=vocab[\"<start>\"],tgt_vocab=vocab)\n",
    "greedy_dec_predict.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor([0.3191]), tensor([0.1875]), tensor([0.3108]))"
      ]
     },
     "execution_count": 98,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "end = train_data[0][2][:80].unsqueeze(0)\n",
    "rouge_l(greedy_dec_predict,end,5)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
